import 'dart:collection';

import 'package:networking/networking.dart';
import 'package:networking/src/core/nw_core.dart';

typedef nw = Networking;

class Networking {
  static HashMap<String, NWCore> nwMap = HashMap();

  static Future<Result<T, NWError>> fire<T>(NWRequest<T> request) async {
    var result = await _fire(request);
    switch (result.e) {
      case ResultEnum.success:
        return Result(success: result.success as T, e: ResultEnum.success);
      case ResultEnum.failure:
        return Result(failure: result.failure, e: ResultEnum.failure);
    }
  }

  static Future<Result> _fire<T>(NWRequest<T> request) async {
    var result = await Networking._send(request);
    switch (result.e) {
      case ResultEnum.success:
        if (request.method == HTTPMethod.HEAD) {
          if ((result.success as Response).headers['etag'] is List) {
            final List<String>? etags =
                (result.success as Response).headers['etag'];
            if (etags?.first is String) {
              return Result.successful(
                  (result.success as Response).headers['etag']![0]);
            }
            var err = NWError(NWErrorCode.etag, null, "请求成功，但是Etag错误");
            return Result.failed(err);
          } else {
            var err = NWError(NWErrorCode.etag, null, "请求成功，但是Etag错误");
            return Result.failed(err);
          }
        } else {
          var rawData = (result.success as Response).data;
          if (rawData == null) {
            var errCode = const NWErrorCode(-2, "请求成功，但是什么数据都没有");
            var err = NWError(errCode, null, "请求成功，但是什么数据都没有");
            return Result.failed(err);
          } else {
            int? code = rawData['code'];
            if (code != 0) {
              String? msg = rawData['msg'];
              if (msg != null) {
                var errCode = NWErrorCode(code!, msg);
                var err = NWError(errCode, null, msg);
                return Result.failed(err);
              } else {
                var errCode =
                    NWErrorCode(code!, msg ?? "请求成功，但是业务代码非0，并且没有msg");
                var err = NWError(errCode, null, "请求成功，但是业务代码非0，并且没有msg");
                return Result.failed(err);
              }
            }
            var data = request.parseData(rawData['data']);
            if (data != null) {
              return Result.successful(data);
            } else {
              var errCode = NWErrorCode.analysis;
              var err = NWError(
                  errCode, null, "${(result.success as Response).data}");
              return Result.failed(err);
            }
          }
        }

      case ResultEnum.failure:
        return result;
    }
  }

  static Future<Result> _send<T>(NWRequest<T> request) async {
    var baseUrl = request.baseUrl();
    if (baseUrl.isEmpty) {
      var err =
          NWError(const NWErrorCode(2, "baseUrl Empty"), null, "baseUrl Empty");
      return Result.failed(err);
    }
    var nw = nwMap[baseUrl];
    if (nw == null) {
      nw = NWCore();
      nwMap[baseUrl] = nw;
    }
    return await nw.send(request);
  }
}

class Result<Success, Failure extends NWError> {
  late Success? success;
  late Failure? failure;
  final ResultEnum e;
  Result({this.success, this.failure, required this.e});

  static Result successful<Success>(Success suc) {
    return Result(success: suc, e: ResultEnum.success);
  }

  static Result failed<Failure extends NWError>(Failure failure) {
    return Result(failure: failure, e: ResultEnum.failure);
  }
  
}

enum ResultEnum {
  success,
  failure,
}
